#ifndef UTILS_HEADER
#define UTILS_HEADER

#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
#include<algorithm>
#include<iterator>
#include<vector>
#include<map>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include "def.hpp"

using namespace std;

template <class T> bool from_string(T& t, const std::string& s, std::ios_base& (*f)(std::ios_base&)){
  std::istringstream iss(s);
  return !(iss >> f >> t).fail();
}

template <class T>
std::string to_string(T t, std::ios_base & (*f)(std::ios_base&))
{
  std::ostringstream oss;
  oss << f << t;
  return oss.str();
}


template<class T>
void allocate_memory(T**& container,const int &m, const int &n){
  container = new T*[m];
  for(int i=0;i<m;i++){
    container[i] = new T[n];
    for (int j=0;j< n;j++)
      container[i][j] = (T)0.0;
  }
}

template<class T>
void dellocate_memory(T**& container,const int &m, const int &n){
  for(int i=0;i<m;i++){
    delete[] container[i];
  }
  delete[] container;
}

double get_sum(double*& buffer, int& K);

double log_sum(double log_a, double log_b);

double log_sub(double log_a, double log_b);

double log_sum_array(double*& buffer, int K);

double log_sum_vector(vector<double>& buffer);

double log_sumexp(double exp_a, double exp_b);

double digamma(double x);

double log_gamma(double x);

double sum_log_gamma(double*& buffer, int& K); // \sum \log \Gamma(x)

double random_gamma_distribution(double shape, double scalar); // generate random numbers from gamma distribution

double random_uniform_distribution(double lower, double upper);

double l1_distance(double*& a, double*& b, int& K);

double l2_distance(double*& a, double*& b, int& K);

double beta_function(double a, double b);

double beta_distribution(double a, double b, double x);

double Trunc(double,double); // truncation function for L1 regularization                                                                                                                                                                  

double Min(double,double);

double Max(double,double);
#endif
